`include "define.v"
module edu
(
	input	wire   	[02:00]         edu_funct3_i,
    input	wire   	[31:00]         edu_instr_i, 
    input	wire   	[01:00]         edu_pc_i,
    input   wire                    edu_instr_system_i,
    input   wire                    edu_instr_load_i,
    input   wire                    edu_instr_store_i,
    input	wire   	[02:00]         edu_mem_addr_i,
    input   wire                    edu_illegal_instr_flag_i,
    //  异常信号
    input   wire                    edu_instr_acc_fault_i,
    input   wire                    edu_load_acc_fault_i,
    input   wire                    edu_store_acc_fault_i,
    //
    output  wire                    edu_instr_addr_misalig_o,
    output  wire                    edu_instr_acc_fault_o  , 
    output  wire                    edu_illegal_instr_o   ,  
    output  wire                    edu_ebreak_o           , 
    output  wire                    edu_load_addr_misalig_o ,
    output  wire                    edu_load_acc_fault_o    ,
    output  wire                    edu_store_addr_misalig_o,
    output  wire                    edu_store_acc_fault_o   ,
    output  wire                    edu_ecall_o             ,
    output  wire                    edu_wfi_flag_o,
    output  wire                    edu_mret_flag_o,
    output  wire                    edu_exc_flag_o
);
    //
    wire                instr_addr_misalig;
    wire                instr_acc_fault;
    wire                illegal_instr;    
    wire                ebreak;           
    wire                load_addr_misalig;
    wire                load_acc_fault;
    wire                store_addr_misalig;
    wire                store_acc_fault;
    wire                ecall;  
    wire                mret; 
    wire                wfi;
    //
    wire                exc_flag;
    wire                irq_flag;
    //  中断裁决


    //  异常判定
    assign      instr_addr_misalig      =   edu_pc_i != 2'b00;
    assign      instr_acc_fault         =   edu_instr_acc_fault_i;
    assign      illegal_instr           =   edu_illegal_instr_flag_i;
    assign      ebreak                  =   edu_instr_system_i && edu_instr_i[31:20]    ==   12'd1;
    assign      load_addr_misalig       =   edu_instr_load_i &&
                                                (
                                                    (edu_instr_i[14:12] == 3'b001 && edu_mem_addr_i[00:00] != 1'b0) ||            //LH
                                                    (edu_instr_i[14:12] == 3'b010 && edu_mem_addr_i[01:00] != 2'b0) ||            //LW
                                                    (edu_instr_i[14:12] == 3'b011 && edu_mem_addr_i[02:00] != 3'b0)          	    //LD
                                                );
    assign      load_acc_fault          =   edu_load_acc_fault_i;                                            
    assign      store_addr_misalig      =   edu_instr_store_i &&
                                                (
                                                    (edu_funct3_i == 3'b001 && edu_mem_addr_i[00:00] != 1'b0) ||          //SH
                                                    (edu_funct3_i == 3'b010 && edu_mem_addr_i[01:00] != 2'b0) ||          //SW
                                                    (edu_funct3_i == 3'b011 && edu_mem_addr_i[02:00] != 3'b0)             //SD
                                                );
    assign      store_acc_fault         =   edu_store_acc_fault_i;
    assign      ecall                   =   edu_instr_system_i &&  edu_instr_i[31:20]         ==  12'b0;
    assign      mret                    =   edu_instr_system_i &&  edu_instr_i[31:25]         ==  7'b0011000      &&
                                                                    edu_funct3_i               ==  3'b0            ;
    //  WFI
    assign      wfi                     =   edu_instr_system_i &&  edu_instr_i[31:25]         ==  7'b0001000      &&
                                                                    edu_funct3_i               ==  3'b0            ; 

    //  
    assign  exc_flag                            =  (   instr_addr_misalig       ||  instr_acc_fault         ||  illegal_instr       || 
                                                        ebreak                  ||  load_addr_misalig       ||  load_acc_fault      || 
                                                        store_addr_misalig      ||  store_acc_fault         ||  ecall               );

	
//----------------------------------------------------------------------------
    // exc_irq_flag
    assign  edu_instr_addr_misalig_o   =   instr_addr_misalig;
    assign  edu_instr_acc_fault_o      =   instr_acc_fault;
    assign  edu_illegal_instr_o        =   illegal_instr;   
    assign  edu_ebreak_o               =   ebreak;          
    assign  edu_load_addr_misalig_o    =   load_addr_misalig;
    assign  edu_load_acc_fault_o       =   load_acc_fault;  
    assign  edu_store_addr_misalig_o   =   store_addr_misalig;
    assign  edu_store_acc_fault_o      =   store_acc_fault;
    assign  edu_ecall_o                =   ecall;         
    assign  edu_mret_flag_o            =   mret;
    assign  edu_wfi_flag_o             =   wfi;
    assign  edu_exc_flag_o             =   exc_flag;


endmodule